package com.example.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.example.exception.ConcurrencyFailException;
import com.example.mapper.ConcurrencySafeMapper;
import com.example.po.ConcurrencySafePO;
import com.example.service.DbConcurrencySafe;
import com.example.utils.IdUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.function.Consumer;
import java.util.function.Supplier;

/*
@description:
@ClassName CasDbConcurrencySafe
@author chen
@create 2025-06-11 17:27
@Version 1.0
*/
@Component
public class CasDbConcurrencySafe implements DbConcurrencySafe
{

    @Resource
    private TransactionTemplate transactionTemplate;


    @Resource
    private ConcurrencySafeMapper concurrencySafeMapper;

    /*
     * @param key   唯一 key
     * @param callback  执行方法
     * @param successCallBack  成功后执行方法
     * @param failCallBack     失败后执行方法
     * @==============History===============<br/>;
     * @Description //
     * @Date 2025/6/11
     */
    @Override
    public <T> T exec(String key,
                      Supplier<T> callback,
                      Consumer<T> successCallBack,
                      Consumer<ConcurrencyFailException> failCallBack)
    {
        return transactionTemplate.execute(status ->
        {

            // 1.获取 ConcurrencySafePO
            ConcurrencySafePO po = this.getAndCreate(key);

            // 2、执行业务操作
            T result = callback.get();

            // 3、乐观锁更新 ConcurrencySafePO
            int updateCount = this.concurrencySafeMapper.optimisticUpdate(po);


            // 成功执行回调
            if (updateCount == 1 && successCallBack != null)
            {
                successCallBack.accept(result);
            }

            if (updateCount == 0)
            {
                //失败，创建一个异常
                ConcurrencyFailException concurrencyFailException = new ConcurrencyFailException(key, "并发修改失败!");

                // 若调用方传入了失败回调的函数failCallBack,那么将执行回调
                if (failCallBack != null)
                {
                    failCallBack.accept(concurrencyFailException);
                } else
                {
                    //兜底，抛出异常，让事务回滚
                    throw concurrencyFailException;
                }
            }
            return result;
        });
    }



    private ConcurrencySafePO getAndCreate(String key)
    {
        ConcurrencySafePO po = this.getByKey(key);
        if (po == null)
        {
            po = new ConcurrencySafePO();
            po.setId(IdUtils.generateId());
            po.setSafeKey(key);
            po.setVersion(0L);
            this.concurrencySafeMapper.insert(po);
        }
        else
        {
            ConcurrencySafePO clonePO = new ConcurrencySafePO();
            BeanUtils.copyProperties(po, clonePO);
            po = clonePO;
        }
        return po;
    }

    private ConcurrencySafePO getByKey(String key)
    {
        LambdaQueryWrapper<ConcurrencySafePO> query =
                Wrappers.lambdaQuery(ConcurrencySafePO.class).eq(ConcurrencySafePO::getSafeKey, key);
        return this.concurrencySafeMapper.selectOne(query);
    }
}
